package tw.com.chttl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;

enum BabyDataType{FOOD_PHOTO(R.drawable.bottle), APPLIANCE_PHOTO(R.drawable.carriage), DAD_PHOTO(R.drawable.dad), MOM_PHOTO(R.drawable.mom);
	BabyDataType(int id){iconID = id;};
	
	int getIconID(){return iconID;}
	
	private int iconID;
};

public class BabyData implements Comparable<BabyData>{		
	BabyData(){
		timeString = String.valueOf((int)(24*Math.random())) + ":" + String.format("%02d",(int)(60*Math.random()));
		type =  Math.random()>3./4?BabyDataType.APPLIANCE_PHOTO:Math.random()>2./3?BabyDataType.FOOD_PHOTO:Math.random()>1./2?BabyDataType.DAD_PHOTO:BabyDataType.MOM_PHOTO;
	}
	
	private final BabyDataType type;
	private final String timeString;
	
	
	String getTime(){
		return timeString;
	};
	
	BabyDataType getType(){
		return type;
	}

	public int compareTo(BabyData obj) {
		String[] thisTime = this.getTime().split(":");
		String[] objTime = obj.getTime().split(":");
		Integer thisHour = Integer.valueOf(thisTime[0]);
		Integer objHour = Integer.valueOf(objTime[0]);
		Integer thisMinute = Integer.valueOf(thisTime[1]);
		Integer objMinute = Integer.valueOf(objTime[1]);
		
		return thisHour.equals(objHour)?thisMinute.compareTo(objMinute):thisHour.compareTo(objHour);
	};
}

class BabyDataThread extends Thread{
	BabyDataThread(int days){daysInPage = days;}
	
	private final int daysInPage;
	private boolean dataUpdated = true; 
	private Calendar calendar = Calendar.getInstance();
	private HashMap<Integer, Integer> startingIndexes = new HashMap<Integer, Integer>();
	private HashMap<Integer, ArrayList<BabyData>> babyDatas = new HashMap<Integer, ArrayList<BabyData>>();
	
	synchronized private void prepareStartingIndexes(){
		Calendar tmpCalendar = Calendar.getInstance();
		
		//clear out-of-scope data
		tmpCalendar.setTime(calendar.getTime());
		tmpCalendar.add(Calendar.DATE, -2*daysInPage);
		for(int i=0;i<daysInPage;i++){
			startingIndexes.remove(tmpCalendar.get(Calendar.DAY_OF_YEAR));
			tmpCalendar.add(Calendar.DATE, 1);
		}
		tmpCalendar.setTime(calendar.getTime());
		tmpCalendar.add(Calendar.DATE, 2*daysInPage);
		for(int i=0;i<daysInPage;i++){
			startingIndexes.remove(tmpCalendar.get(Calendar.DAY_OF_YEAR));
			tmpCalendar.add(Calendar.DATE, 1);
		}
		
		//prepare in-scope data
		tmpCalendar.setTime(calendar.getTime());
		tmpCalendar.add(Calendar.DATE, -daysInPage);
		for(int i=0;i<3*daysInPage;i++){
			Integer index = startingIndexes.get(tmpCalendar.get(Calendar.DAY_OF_YEAR));
			if(index==null)
				startingIndexes.put(tmpCalendar.get(Calendar.DAY_OF_YEAR), 0);
			
			tmpCalendar.add(Calendar.DATE, 1);
		}
	}
	
	synchronized private void prepareBabyData(){
		Calendar tmpCalendar = Calendar.getInstance();
		
		//clear out-of-scope data
		tmpCalendar.setTime(calendar.getTime());
		tmpCalendar.add(Calendar.DATE, -2*daysInPage);
		for(int i=0;i<daysInPage;i++){
			int dayOfYear = tmpCalendar.get(Calendar.DAY_OF_YEAR);
			ArrayList<BabyData> array = babyDatas.get(dayOfYear);
			if(array!=null){
				array.clear();
				babyDatas.remove(dayOfYear);
			}
			tmpCalendar.add(Calendar.DATE, 1);
		}
		tmpCalendar.setTime(calendar.getTime());
		tmpCalendar.add(Calendar.DATE, 2*daysInPage);
		for(int i=0;i<daysInPage;i++){
			int dayOfYear = tmpCalendar.get(Calendar.DAY_OF_YEAR);
			ArrayList<BabyData> array = babyDatas.get(dayOfYear);
			if(array!=null){
				array.clear();
				babyDatas.remove(dayOfYear);
			}
			
			tmpCalendar.add(Calendar.DATE, 1);
		}
		
		//prepare in-scope data
		tmpCalendar.setTime(calendar.getTime());
		tmpCalendar.add(Calendar.DATE, -daysInPage);
		for(int i=0;i<3*daysInPage;i++){
			int dayOfYear = tmpCalendar.get(Calendar.DAY_OF_YEAR);
			
			ArrayList<BabyData> array = babyDatas.get(dayOfYear);
			if(array==null){
				array = new ArrayList<BabyData>();
				
				int numSim = (int)(7 * Math.random());
				for(int j=0;j<numSim;j++)
					array.add(new BabyData());
				babyDatas.put(dayOfYear, array);
			}
			
			//sort the baby data according to the time
			Collections.sort(array);
			
			tmpCalendar.add(Calendar.DATE, 1);
		}
	}
	
	//note that calling this function will make run() continue to update data
	synchronized void setCalendar(Calendar cal){
		calendar.setTime(cal.getTime());
		dataUpdated = false;
		this.notifyAll();
	}	
	
	synchronized Integer getStartingIndex(Integer key){
		return startingIndexes.get(key);
	}
	
	synchronized HashMap<Integer, Integer> getStartingIndexesCopy(){
		HashMap<Integer, Integer> copyHashMap = new HashMap<Integer, Integer>();
		copyHashMap.putAll(startingIndexes);
		return copyHashMap;
	}
	
	synchronized void setStartingIndex(Integer key, Integer value){
		startingIndexes.put(key, value);
	}

	synchronized int getNumBabyDataInDay(int DayOfYear){
		return babyDatas.get(DayOfYear).size();
	}
	
	synchronized BabyData getBabyData(int DayOfYear, int index){		
		return babyDatas.get(DayOfYear).get(index);
	}
	
	
	//this thread is used to prepare the babyData in background
	@Override
	synchronized public void run() {
		while(true){
			//if the babyData is already up to date
			while(dataUpdated){
				try{
					//wait until notified (when setCalendar() is called by UI thread)
					this.wait();
				}
				catch(InterruptedException ex){	}
			}
			
			prepareStartingIndexes();
			prepareBabyData();
				
			dataUpdated = true;
		}	
	}			
}
